package org.syncsoft.overalt.gui.api.window;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JOptionPane;

import org.syncsoft.overalt.common.api.Resource;
import org.syncsoft.overalt.common.exception.SystemException;
import org.syncsoft.overalt.communication.exception.LoginException;
import org.syncsoft.overalt.core.api.Core;
import org.syncsoft.overalt.core.api.ICore;
import org.syncsoft.overalt.domain.community.entity.Community;
import org.syncsoft.overalt.domain.document.entity.Permission;
import org.syncsoft.overalt.domain.tag.entity.Tag;
import org.syncsoft.overalt.gui.api.WindowContextValue;

/**
 * Abstract window controller
 * 
 * @author tptfc
 *
 */
public abstract class AbstractWindowController<T extends AbstractWindow> {
	protected T window;
	protected LoginWindow login;
	
	protected abstract T doCreateWindow() throws SystemException;
	protected abstract void doSubmit(WindowContextValue context) throws SystemException;
	
	/**
	 * start controller
	 */
	public void start() {
		createWindow();
	}
	
	/**
	 * submit the values to server
	 * 
	 * @param context
	 */
	public void submit(WindowContextValue context) {
		try {
			doSubmit(context);
			getWindow().close();
			alertSuccess(Resource.getProperty("overalt.text.success.operation"));
		} catch (LoginException e) {
			getWindow().setEnable(false);
			createLoginWindow();
		} catch (SystemException e) {
			alertError(e.getMessage());
		} catch (Exception e) {
			alertError(Resource.getProperty("overalt.text.error.internal.error"));
			closeWindows();
		}
	}
	
	/**
	 * create window
	 */
	protected void createWindow() {
		try {
			setWindow(doCreateWindow());
			updateWindow();
			getWindow().show();
		} catch (LoginException e) {
			createLoginWindow();
		} catch (SystemException e) {
			alertError(e.getMessage());
		} catch (Exception e) {
			alertError(Resource.getProperty("overalt.text.error.internal.error"));
			closeWindows();
		}
	}

	/**
	 * update window state
	 * 
	 * @precondition getWindow() not is null
	 * 
	 * @throws SystemException
	 */
	protected void updateWindow() throws SystemException {
		if (getWindow() != null) {
			getWindow().update(getUpdateWindowContextValue());
		}
	}
	
	/**
	 * template method
	 * @return
	 */
	protected WindowContextValue getUpdateWindowContextValue() {
		return new WindowContextValue();
	}

	/**
	 * create login window
	 */
	protected void createLoginWindow() {
		if (getLogin() == null || !getLogin().isOpened()) {
			setLogin(new LoginWindow(this));
			getLogin().show();
		}
	}
	
	void login(WindowContextValue context) {
		try {
			getLogin().setEnable(false);
			String login = context.getValue("login");
			String passsword = context.getValue("password");
			getCore().login(login, passsword);
			getLogin().close();
			
			if (getWindow() == null) {
				createWindow();
			} else {
				getWindow().setEnable(true);
			}
			
		} catch (LoginException e) {
			getLogin().setEnable(true);
			alertError(Resource.getProperty("overalt.text.error.invalid.login"));
		} catch (SystemException e) {
			getLogin().setEnable(true);
			alertError(e.getMessage());
		} catch (Exception e) {
			alertError(Resource.getProperty("overalt.text.error.internal.error"));
			closeWindows();
		}
		
	}
	
	/**
	 * function to cancel login
	 */
	void cancelLogin() {
		getLogin().close();
		
		if (getWindow() != null) {
			getWindow().setEnable(true);
		}
	}
	
	/**
	 * 
	 * @param error
	 */
	private void alertError(String error) {
		JOptionPane.showMessageDialog(null, error, "Error", JOptionPane.ERROR_MESSAGE);
	}
	
	/**
	 * 
	 * @param error
	 */
	private void alertSuccess(String success) {
		JOptionPane.showMessageDialog(null, success, "Success", JOptionPane.ERROR_MESSAGE);
	}
	
	/**
	 * @precondition tags != null
	 * @postcondition return a empty collection if contains error in parse or no
	 * @param tags
	 * @return
	 */
	protected Set<Tag> parseTags(String tags) {
		Set<Tag> tagsCollection = new HashSet<Tag>();
		
		if (tags != null) {
			String arrayTags[] = tags.trim().split(",");
			
			for (String stringTag : arrayTags) {
				Tag tag = new Tag();
				tag.setDescription(stringTag.trim());
				tagsCollection.add(tag);
			}
		}
		
		return tagsCollection;
	}
	
	/**
	 * 
	 * @param communitiesCode
	 * @return
	 */
	protected Set<Community> parseCommunities(Collection<Integer> communitiesCode) {
		Set<Community> communities = new HashSet<Community>();
		
		if (communitiesCode != null) {
			for (int code : communitiesCode) {
				try {
					Community community = new Community();
					community.setCode(code);
					communities.add(community);
				} catch (NumberFormatException e) {
					continue;
				}
			}
		}
		
		return communities;
	}
	
	/**
	 * 
	 * @param permission
	 * @return
	 */
	protected Permission parsePermission(String permission) {
		Permission permissionValue = Permission.PUBLIC;
		
		if (Resource.getProperty("overalt.label.private").equals(permission)) {
			permissionValue = Permission.PRIVATE;
		}
		
		return permissionValue;
	}
	

	/**
	 * close windows
	 */
	private void closeWindows() {
		if (getWindow() != null) {
			getWindow().close();
		}
		
		if (getLogin() != null) {
			getLogin().close();
		}
	}
	
	/**
	 * 
	 * @return
	 */
	protected ICore getCore() {
		return Core.getInstance();
	}
	protected T getWindow() {
		return window;
	}
	protected void setWindow(T window) {
		this.window = window;
	}
	private LoginWindow getLogin() {
		return login;
	}
	private void setLogin(LoginWindow login) {
		this.login = login;
	}
}
